'use strict';

const Service = require('egg').Service;

module.exports = class ArticleService extends Service {

  constructor(ctx) {
    super(ctx);

    // //// Attributes //////////////////////////////////////////

    // Public
    this.id = 0;
    this.authorID = 0;
    this.author = '';
    this.category;
    this.categoryID = 0;
    this.title = '';
    this.content0 = '';
    this.content1 = '';
    this.comments;
    this.trackbacks;
    this.editMark = '';
    this.postTime = new Date();
    this.IP = '';
    this.mode;
    this.locked = false;
    this.selected = false;
    this.ubbFlags = '';
    this.viewCount;
    this.commentCount;
    this.trackbackURL = '';
    this.trackbackCount;
    this.trackbackAgain = false;
    this.nextArticle;
    this.prevArticle;
  }

  // Load Article --------------------------
  async load(strSelect, strWhere) {
    const tmpA = await this.ctx.app.connBlog.query('SELECT ' + strSelect + ' FROM blog_article WHERE ' + strWhere, 1, 1);
    if (tmpA && tmpA.length) {
      await this.fill(tmpA[0]);
      return true;
    }
    return false;

  }

  // Load Article By ID --------------------
  async loadByID(intID, bLoadSideArticle) {
    if (!this.ctx.helper.checkInt(intID)) {
      return this.ctx.__('invalid_parameter');
    }
    // Load from cache
    const article = await this.ctx.app.theCache.getArticleByID(intID);
    if (article) {
      await this.fill(article);
      return false;
    }
    // Load from DB
    if (await this.load('*', 'log_ID=' + this.ctx.helper.checkInt(intID))) {
      return false;
    }
    return this.ctx.__('article_not_found');

  }

  // Fill Article Object -------------------
  async fill(arr) {
    this.id = arr.log_id;
    this.author = arr.log_author;
    this.authorID = arr.log_authorID;
    this.categoryID = arr.log_catID;
    this.category = await this.ctx.app.theCache.getCategoryByID(this.categoryID);
    this.title = arr.log_title;
    this.content0 = arr.log_content0;
    this.content1 = arr.log_content1;
    this.editMark = arr.log_editMark;
    this.postTime = arr.log_postTime;
    this.IP = arr.log_ip;
    this.mode = arr.log_mode;
    this.locked = arr.log_locked;
    this.selected = arr.log_selected;
    this.ubbFlags = arr.log_ubbFlags;
    this.viewCount = arr.log_viewCount;
    this.commentCount = arr.log_commentCount;
    this.trackbackCount = arr.log_trackbackCount;
    this.trackbackURL = arr.log_trackbackURL;
    this.disableTrackback = arr.log_disableTrackback;
  }

  // Load Side Article --------------------------
  async loadSideArticle() {
    this.nextArticle = await this.getSideArticle(true);
    this.prevArticle = await this.getSideArticle(false);
  }

  // Get Side Article --------------------------
  async getSideArticle(bNext) {
    return false;// todo 调整日期查询处理方法
    // Construct SQL String
    let sql = 'SELECT log_ID,log_Title FROM blog_article WHERE log_PostTime';
    if (bNext) {
      sql += '>';
    } else {
      sql += '<';
    }
    sql += this.ctx.helper.getDateTimeString('', this.postTime);

    if (this.ctx.theUser.rights.view < 1) {
      return false;
    }
    if (this.ctx.theUser.rights.view == 1)
      sql += this.ctx.theUser.loggedIn ? 'AND log_mode<3' : 'AND log_mode=1';
    if (this.ctx.theUser.rights.view < 2) {
      for (let i = 0; i < this.ctx.app.theCache.categories.length; i++) {
        if (this.ctx.app.theCache.categories[i].hidden)
          sql += ' AND log_catid<>' + this.ctx.app.theCache.categories[i].id;
      }
    }
    if (this.ctx.theUser.rights.view == 2) {
      sql += 'AND log_mode<4';
    }

    sql += ' ORDER BY log_PostTime';
    if (bNext) {
      sql += ' ASC';
    } else {
      sql += ' DESC';
    }

    // Query
    const tmpA = await this.ctx.app.connBlog.query(sql, 1, 1);
    if (tmpA && tmpA.length) {
      return {
        id: tmpA[0].log_id,
        title: tmpA[0].log_title
      };
    }
    return false;

  }

  // Load Comments --------------------------
  async loadComments(bTimeOrder, bWithTrackBack, intTrackbackPos, intPageSize, intCurrentPage) {
    let sql = 'SELECT 0 as type, comm_id,comm_content,comm_authorID,comm_author,comm_postTime,comm_editMark,comm_ubbFlags,comm_hidden,comm_ip FROM blog_comment WHERE log_id=' + this.id;

    if (bWithTrackBack) {
      // Trackback Fields Mapping: comm_ID=0, comm_Content=tb_Excerpt, comm_authorID=tb_ID, comm_author=tb_Title
      sql += ' UNION ALL SELECT 1 as type ,0 as comm_id,tb_Excerpt as comm_content,tb_ID as comm_authorID,tb_Title as comm_author,tb_Time as comm_postTime,tb_URL as comm_editMark,tb_Blog as comm_ubbFlags,0 as comm_hidden,tb_IP as comm_ip FROM blog_trackback WHERE log_id=' + this.id;
    }

    sql += ' ORDER BY';
    if (bWithTrackBack) {
      if (intTrackbackPos == 1) {
        sql += ' type DESC,';
      } else if (intTrackbackPos == 2) {
        sql += ' type ASC,';
      }
    }
    if (bTimeOrder) {
      sql += ' comm_postTime DESC';
    } else {
      sql += ' comm_postTime ASC';
    }

    // Get data
    let tmpA;
    if (intPageSize > 0) {
      tmpA = await this.ctx.app.connBlog.query(sql, intPageSize, this.ctx.query.page, false);
    } else {
      tmpA = await this.ctx.app.connBlog.query(sql);
    }

    if (tmpA && tmpA.length) {
      this.comments = {};
      for (let i = 0; i < tmpA.length; i++) {
        if (tmpA[i].type == 0) {
          // normal comment
          this.comments[i] = {
            type: 0,
            id: tmpA[i].comm_id,
            content: tmpA[i].comm_content,
            authorID: tmpA[i].comm_authorID,
            author: tmpA[i].comm_author,
            postTime: new Date(tmpA[i].comm_postTime),
            editMark: tmpA[i].comm_editMark,
            ubbFlags: tmpA[i].comm_ubbFlags,
            hidden: tmpA[i].comm_hidden,
            IP: tmpA[i].comm_ip,
          };
        } else {
          // trackback entry
          this.comments[i] = {
            type: 1,
            id: tmpA[i].comm_authorID,
            excerpt: tmpA[i].comm_content,
            title: tmpA[i].comm_author,
            time: new Date(tmpA[i].comm_postTime),
            IP: tmpA[i].comm_ip,
            url: tmpA[i].comm_editMark,
            blog: tmpA[i].comm_ubbFlags,
          };
        }
      }
      return this.ctx.app.connBlog.recordCount;
    }

    this.comments = false;
    return 0;
  }

  // Fill Article Object From Edit Form Data -------------------
  async fillFromPost(bEdit) {
    let strError = '';
    const input = this.ctx.request.body;
    // Get Data
    if (!input.log_title || !input.log_catid || !input.message) {
      strError += '<li>' + this.ctx.__('form_incomplete') + '</li>';
    }

    this.categoryID = this.ctx.helper.checkInt(input.log_catid);
    // Check If the Category Exists
    this.category = await this.ctx.app.theCache.getCategoryByID(this.categoryID);
    if (this.category.id == 0) {
      strError += '<li>' + this.ctx.__('invalid_cat') + '</li>';
    }

    this.mode = this.ctx.helper.checkInt(input.log_mode);
    if (this.mode == 0) {
      strError += '<li>' + this.ctx.__('invalid_mode') + '</li>';
    }

    this.title = this.ctx.helper.trim(input.log_title);
    if (this.title.length < 1 || this.title.length > 255) {
      strError += '<li>' + this.ctx.__('title_invalid') + '</li>';
    }

    this.postTime = this.ctx.helper.parseDateTime(input.log_posttime);
    if (this.postTime == null) this.postTime = new Date();

    this.ubbFlags = '';
    this.ubbFlags += input.e_ubb == 'true' ? '1' : '0';
    this.ubbFlags += input.e_autourl == 'true' ? '1' : '0';
    this.ubbFlags += input.e_image == 'true' ? '1' : '0';
    this.ubbFlags += input.e_media == 'true' ? '1' : '0';
    this.ubbFlags += input.e_smilies == 'true' ? '1' : '0';
    this.ubbFlags += '1'; // bTextBlock - always 1
    if (input.e_html == 'true') this.ubbFlags = 'html';

    this.content0 = this.ctx.helper.trim(input.message);
    this.content1 = '';
    if (this.ubbFlags == 'html') {
      // Clean up the HTML a little
      this.content0 = this.ctx.helper.cleanHTML(this.content0);
      this.content0 = this.ctx.helper.closeHTML(this.content0);
    }
    if (this.content0.length < 2) {
      strError += '<li>' + this.ctx.__('content_blank') + '</li>';
    } else {
      // Split Content
      let pos = this.content0.indexOf('[separator]');
      if (pos > 0) {
        this.content1 = this.content0.substr(pos);
        this.content0 = this.content0.substr(0, pos);
      } else if (this.ctx.app.theCache.settings.enableContentAutoSplit == 1
        && this.content0.length > this.ctx.app.theCache.settings.contentAutoSplitChars) {
        const intLength = this.ctx.app.theCache.settings.contentAutoSplitChars;
        if (this.ubbFlags == 'html') {
          pos = this.getSplitPosHTML(this.content0, intLength);
        } else {
          pos = this.getSplitPos(this.content0, intLength);
        }
        if (pos != false) {
          this.content1 = this.content0.substr(pos);
          this.content0 = this.content0.substr(0, pos);
        }
      }
    }

    // Data that needs no validation
    if (bEdit)
      this.editMark = this.ctx.theUser.username + '$|$' + this.ctx.helper.getDateTimeString();
    this.IP = this.ctx.theUser.IP;
    this.locked = input.log_locked == 'true';
    this.selected = input.log_selected == 'true';

    // Check if we need to send a trackback again
    if (this.trackbackURL != input.log_trackbackurl) this.trackbackAgain = true;
    this.trackbackURL = this.ctx.helper.trim(input.log_trackbackurl);

    return strError;
  }

  // Get Auto Split Position
  getSplitPos(str, intChars) {
    // Check if the text block left behind is big enough
    if (str.length <= intChars || intChars == 0) return false;
    if (str.length <= intChars + 50) return false;

    // Snap to the Nearest Space Char
    let nearReturnChar = str.indexOf(' ', intChars - 10);
    if (nearReturnChar > -1 && nearReturnChar < intChars + 30) intChars = nearReturnChar + 1;
    // Snap to the Nearest UBB tag
    nearReturnChar = str.indexOf('[/', intChars - 10);
    if (nearReturnChar > -1) nearReturnChar = str.indexOf(']', nearReturnChar);
    if (nearReturnChar > -1 && nearReturnChar < intChars + 30) intChars = nearReturnChar + 1;
    // Snap to the Nearest New Line Char
    nearReturnChar = str.indexOf('\n', intChars - 10);
    if (nearReturnChar > -1 && nearReturnChar < intChars + 30) intChars = nearReturnChar + 1;

    return intChars;
  }

  // Get Auto Split Position For HTML Content
  getSplitPosHTML(str, intChars) {
    // Check if the text block left behind is big enough
    if (str.length <= intChars || intChars == 0) return false;
    if (str.length <= intChars + 80) return false;

    // Caculate tags length in area
    intChars += intChars - this.ctx.helper.trimHTML(str.substr(0, intChars)).length;

    // Snap to the Nearest Space Char
    let nearCloseTag = str.indexOf(' ', intChars - 10);
    if (nearCloseTag > -1 && nearCloseTag < intChars + 30) intChars = nearCloseTag + 1;
    // Snap to the <br/> tag
    nearCloseTag = str.indexOf('<br/>', intChars - 10);
    if (nearCloseTag > -1 && nearCloseTag < intChars + 30) intChars = nearCloseTag + 5;
    // Snap to a close tag
    nearCloseTag = str.indexOf('</', intChars - 10);
    if (nearCloseTag > -1) nearCloseTag = str.indexOf('>', nearCloseTag);
    if (nearCloseTag > -1 && nearCloseTag < intChars + 30) intChars = nearCloseTag + 1;

    return intChars;
  }

  // Update --------------------------
  async update() {
    const arrUpdate = {
      log_catID: this.categoryID,
      log_title: this.title,
      log_content0: this.content0,
      log_content1: this.content1,
      log_ip: this.ctx.theUser.IP,
      log_editMark: this.editMark,
      log_trackbackURL: this.trackbackURL,
      log_mode: this.mode,
      log_postTime: this.postTime,
      log_locked: this.locked,
      log_selected: this.selected,
      log_ubbFlags: this.ubbFlags,
    };
    await this.ctx.app.connBlog.update('blog_article', arrUpdate, 'log_id=' + this.id);
  }

  // Insert --------------------------
  async insert() {
    const arrInsert = {
      log_catID: this.categoryID,
      log_authorID: this.ctx.theUser.id,
      log_author: this.ctx.theUser.username,
      log_title: this.title,
      log_content0: this.content0,
      log_content1: this.content1,
      log_ip: this.ctx.theUser.IP,
      log_trackbackURL: this.trackbackURL,
      log_mode: this.mode,
      log_postTime: this.postTime,
      log_locked: this.locked,
      log_selected: this.selected,
      log_ubbFlags: this.ubbFlags,
    };
    await this.ctx.app.connBlog.insert('blog_article', arrInsert);
    await this.ctx.app.connBlog.updateSQL('blog_settings', { set_value0: this.ctx.app.connBlog.literal('set_value0+1') }, { set_name: 'counterArticle' });
    await this.ctx.app.theCache.updateGlobalCounter('counterArticle', 1);
  }

  async doDelete() {
    await this.ctx.app.connBlog.doDelete('blog_article', 'log_id=' + this.id);
    await this.ctx.app.connBlog.doDelete('blog_comment', 'log_id=' + this.id);
    await this.ctx.app.connBlog.doDelete('blog_trackback', 'log_id=' + this.id);
    await this.ctx.app.connBlog.updateSQL('blog_settings', { set_value0: this.ctx.app.connBlog.literal('set_value011') }, { set_name: 'counterArticle' });
    await this.ctx.app.theCache.updateGlobalCounter('counterArticle', -1);
  }

}
